package com.google.gwt.user.cellview.client;

import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.ProvidesKey;

public class DragCellList<T> extends CellList<T> {

	private T draggingValue;
	private Context draggingContext;
	private Element draggingCellParent;

	public DragCellList(Cell<T> cell) {
		super(cell);
	}

	public DragCellList(Cell<T> cell, com.google.gwt.user.cellview.client.CellList.Resources resources) {
		super(cell, resources);
	}

	public DragCellList(Cell<T> cell, ProvidesKey<T> keyProvider) {
		super(cell, keyProvider);
	}

	public DragCellList(Cell<T> cell, com.google.gwt.user.cellview.client.CellList.Resources resources,
			ProvidesKey<T> keyProvider) {
		super(cell, resources, keyProvider);
	}

	@Override
	protected void onBrowserEvent2(Event event) {
		super.onBrowserEvent2(event);

		String eventType = event.getType();
		boolean isMouseMove = "mousemove".equals(eventType);
		boolean isMouseUp = "mouseup".equals(eventType);

		boolean isDraggingEvent = (isMouseMove || isMouseUp);

		if (isDraggingEvent && this.draggingValue != null) {
			boolean isSelectionHandled = getCell().handlesSelection()
					|| KeyboardSelectionPolicy.BOUND_TO_SELECTION == getKeyboardSelectionPolicy();
			boolean cellIsEditing = getCell().isEditing(this.draggingContext, this.draggingCellParent,
					this.draggingValue);
			CellPreviewEvent<T> previewEvent = CellPreviewEvent.fire(this, event, this, this.draggingContext,
					this.draggingValue, cellIsEditing, isSelectionHandled);

			if (!previewEvent.isCanceled()) {
				fireEventToCell(this.draggingContext, event, this.draggingCellParent, this.draggingValue);
			}
		}
	}

	public void startDrag(Context context, Element parent, T value) {
		this.draggingValue = value;
		this.draggingContext = context;
		this.draggingCellParent = parent;
		DOM.setCapture((com.google.gwt.user.client.Element) parent.getFirstChildElement());
	}

	public boolean isDragging(T value) {
		return (value.equals(this.draggingValue));
	}

	public boolean isDragging() {
		return (this.draggingValue != null);
	}

	public T endDrag() {
		T result = this.draggingValue;
		if (this.draggingCellParent != null) {
			DOM.releaseCapture((com.google.gwt.user.client.Element) this.draggingCellParent.getFirstChildElement());
		}
		this.draggingValue = null;
		this.draggingCellParent = null;
		this.draggingContext = null;

		return result;
	}

}
